fix: handle None output in parse_response()#3453
Conversation
Guard against empty type args when using bare dict or list annotations (no type parameters, e.g. instead of ). Previously: - construct_type() raised ValueError on bare dict - construct_type() raised IndexError on bare list - _transform_recursive() raised IndexError on bare dict Now these cases gracefully return the data as-is, matching the behavior of parameterized types when the data already matches. Fixes openai#3338, openai#3341
…I responses Fixes openai#3179 The API can return null for the action field in web search calls (e.g., when the search is still in progress or the action hasn't been determined yet). This change makes the action field Optional[Action] with a default of None, matching the actual API behavior. This allows users to safely check action.type without getting an AttributeError when action is None.
When NO_PROXY or other proxy environment variables contain newline characters (common in Docker, .env files, or shell scripts), httpx's get_environment_proxies() only splits by comma and fails with InvalidURL. This fix adds sanitize_proxy_env_vars() that removes newlines from proxy environment variables before httpx reads them. Fixes openai#3303
The ActionSearchSource type only supported type='url' with a required url field, but the API returns specialized data sources (weather, sports, finance) with type='api', a name field, and url=None. Changes: - Add 'api' to the type Literal in both response and param types - Make url optional (absent when type='api') - Add optional name field for the data source identifier Fixes openai#2736
The error event check inside the `if sse.event.startswith("thread.")` block
was unreachable because "error" never starts with "thread.". This meant
error events from the SSE stream were silently ignored in the thread event
path, instead of raising an APIError.
Fix: Move error event handling to the top of the event loop, before the
thread.* check, so error events are always handled regardless of context.
Fixes openai#2796
When response.output is None (e.g., from Codex backend), parse_response() would crash with TypeError: 'NoneType' object is not iterable. This fix adds a defensive check to treat None output as an empty list, preventing the crash while maintaining backward compatibility. Fixes openai#3312, openai#3313, openai#3314, openai#3321
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b553f82c10
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data | ||
| if sse.event and sse.event.startswith("thread."): | ||
| # Handle error events first - these can occur outside of thread.* events | ||
| if sse.event == "error": |
There was a problem hiding this comment.
Preserve assistant error events in streams
When streaming Assistants endpoints such as beta.threads.runs.create(..., stream=True), the request options set synthesize_event_and_data=True and AssistantStreamEvent explicitly includes an event == "error" variant, so an SSE event: error with the assistant ErrorObject payload should be wrapped and yielded to the assistant event handler. This early branch raises APIError before process_data can synthesize {data, event}, which prevents registered on_event consumers from seeing the typed error event and can also replace the server's message with the generic fallback when the payload is not wrapped under an error key; the same issue exists in the async block below.
Useful? React with 👍 / 👎.
Description
This PR fixes a bug where
parse_response()crashes withTypeError: 'NoneType' object is not iterablewhenresponse.outputisNone.Problem
When streaming responses from certain backends (like the ChatGPT Codex backend at
chatgpt.com/backend-api/codex), theresponse.completedevent can containoutput: nullinstead of an empty list. The SDK'sparse_response()function iterates overresponse.outputwithout checking forNone, causing a crash.Affected issues: #3312, #3313, #3314, #3321
Stack trace:
Solution
Added a defensive check in
parse_response()to treatNoneoutput as an empty list:Testing
test_parse_response_with_none_output()that verifies the fixImpact
This fix allows the SDK to gracefully handle responses with
Noneoutput instead of crashing, which is important for compatibility with certain backends like the Codex backend.